﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Resources;
using Loki.Resources;

namespace Loki.Utils
{
    /// <summary>
    /// Tool class for parsing / getting text version of enum values.
    /// </summary>
    /// <typeparam name="T">Type parameter.</typeparam>
    public static class EnumParser<T>
    {
        #region Log
        private static Lazy<ILog> _Log = new Lazy<ILog>(() => LokiServices.Logger.GetLogger(typeof(EnumParser<T>).FullName));

        /// <summary>
        /// Gets the logger.
        /// </summary>
        /// <value>The logger.</value>
        private static ILog Log
        {
            get
            {
                return _Log.Value;
            }
        }
        #endregion

        #region Resource manager
        private static Lazy<ResourceManager> _ResourceManager = new Lazy<ResourceManager>(LoadManager);

        /// <summary>
        ///  Gets the cached ResourceManager instance used by this class.
        /// </summary>
        internal static ResourceManager ResourceManager
        {
            get
            {
                return _ResourceManager.Value;
            }
        }

        private static ResourceManager LoadManager()
        {
            ResourceManager L_ResourceManager = null;
            Type L_Type = typeof(T);
            string[] L_ResourcesNames = L_Type.Assembly.GetManifestResourceNames();

            foreach (string L_ResourceName in L_ResourcesNames)
            {
                if (L_ResourceName.EndsWith(L_Type.Name + RESOURCE_EXTENSION, StringComparison.OrdinalIgnoreCase))
                {
                    Log.DebugFormat(LogStrings.Utils_EnumParser_ManagerFound, L_ResourceName, L_Type.Name);
                    L_ResourceManager = new ResourceManager(L_ResourceName.Replace(RESOURCE_EXTENSION, string.Empty), L_Type.Assembly);
                    break;
                }
            }

            // error : not found
            if (L_ResourceManager == null)
            {
                throw LokiServices.Errors.BuildErrorFormat<MissingManifestResourceException>(ErrorMessages.Utils_EnumParser_ResourceNotFound, Log, L_Type.Name);
            }
            else
            {
                return L_ResourceManager;
            }
        }

        private const string RESOURCE_EXTENSION = ".resources";
        #endregion

        #region Values
        private static Lazy<Dictionary<string, T>> _Values = new Lazy<Dictionary<string, T>>(LoadValues);

        /// <summary>
        /// Gets the list of conversion values.
        /// </summary>
        internal static Dictionary<string, T> Values
        {
            get
            {
                return _Values.Value;
            }
        }

        private static Dictionary<string, T> LoadValues()
        {
            Dictionary<string, T> L_Values = new Dictionary<string, T>();
            try
            {
                ResourceSet L_Set = ResourceManager.GetResourceSet(Culture, true, true);

                IDictionaryEnumerator L_SetEnumerator = L_Set.GetEnumerator();

                // Iterate through the ResourceSet and display the contents to the console. 
                while (L_SetEnumerator.MoveNext())
                {
                    L_Values.Add(L_SetEnumerator.Value.ToString(), (T)Enum.Parse(typeof(T), L_SetEnumerator.Key.ToString()));
                }
            }
            catch (MissingManifestResourceException)
            {
                foreach (var L_Item in Enum.GetValues(typeof(T)))
                {
                    L_Values.Add(L_Item.ToString(), (T)L_Item);
                }
            }

            return L_Values;
        }
        #endregion

        private static CultureInfo _Culture = CultureInfo.CurrentUICulture;

        /// <summary>
        ///   Gets or sets the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        internal static CultureInfo Culture
        {
            get
            {
                return _Culture;
            }

            set
            {
                _Culture = value;
            }
        }

        /// <summary>
        /// Tries to parsing the specified string.
        /// </summary>
        /// <param name="P_DataToParse">The data to parse.</param>
        /// <param name="P_Result">The result.</param>
        /// <returns><c>true</c> if the parsing result is correct, otherwise <c>false</c>.</returns>
        public static bool TryParse(string P_DataToParse, out T P_Result)
        {
            if (Values.ContainsKey(P_DataToParse))
            {
                P_Result = Values[P_DataToParse];
                return true;
            }
            else
            {
                P_Result = default(T);
                return false;
            }
        }

        /// <summary>
        /// Parses the specified string according the enum resources.
        /// </summary>
        /// <param name="P_DataToParse">The string to parse.</param>
        /// <remarks>Reverses the <see cref="ToText(T)" /> function.</remarks>
        public static T Parse(string P_DataToParse)
        {
            return Values[P_DataToParse];
        }

        /// <summary>
        /// Parses the specified string.
        /// </summary>
        /// <param name="P_DataToParse">The string to parse.</param>
        /// <returns>Reverses the enum "ToString" function.</returns>
        public static T DirectParse(string P_DataToParse)
        {
            return (T)Enum.Parse(typeof(T), P_DataToParse, true);
        }

        /// <summary>
        /// Converts the enum value to it's string representation.
        /// </summary>
        /// <remarks>Reverses the <see cref="Parse"/> function.</remarks>
        /// <param name="P_Data">The value to convert.</param>
        /// <returns>The converted value.</returns>
        public static string ToText(T P_Data)
        {
            return ToText(P_Data, Culture);
        }

        /// <summary>
        /// Converts the enum value to it's string representation.
        /// </summary>
        /// <param name="P_Data">The data.</param>
        /// <param name="P_Culture">The culture.</param>
        public static string ToText(T P_Data, CultureInfo P_Culture)
        {
            try
            {
                string L_ReturnData = ResourceManager.GetString(P_Data.ToString(), P_Culture);
                return L_ReturnData == null ? P_Data.ToString() : L_ReturnData;
            }
            catch (MissingManifestResourceException)
            {
                return P_Data.ToString();
            }
        }
    }
}
